package com.uzhie.util;

import com.google.common.base.Strings;
import com.uzhie.exception.SessionException;
import com.uzhie.web.module.User;

import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * Created by lilongfei on 2018/7/16.
 */
public class SessionUtil {

    private org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(this.getClass());

    private ConcurrentMap<String, Session> sessions;
    private long overTime;
    private long checkTime;
    private Timer timer = new Timer("platSessionManagerThread", true);

    // 设置session超时时间 (单位:秒)
    public void setOverTime(long overTime) {
        this.overTime = overTime;
    }

    // 设置轮询检查session时间 (单位:毫秒)
    public void setCheckTime(long checkTime) {
        this.checkTime = checkTime;
        this.scheduler();
    }

    private SessionUtil() {
        logger.info(SessionException.SESSIONMANAGER_START);
        this.sessions = new ConcurrentHashMap<>();
    }

    public void destroy() {
        logger.info("enter method destroy");
        timer.cancel();
        logger.info("终止 平台 session 管理任务");
    }


    /**
     * 判断session是否超时
     *
     * @return true 超时, false 不超时
     */
    public boolean isOverTime(@NotNull Session session) {
        if (System.currentTimeMillis() / 1000 - session.getUpdateTime() / 1000 > overTime)
            return true;
        return false;
    }

    /**
     * 通过requestCode获取服务器缓存的session值
     *
     * @param requestCode 用户requestCode ,默认userCode
     * @return 用户session 如果用户session不存在,返回null
     * @throws NoSuchFieldException 如果session属性不存在,则抛出异常
     */
    public Session get(String requestCode) throws NoSuchFieldException {
        if (sessions == null) throw new NoSuchFieldException(SessionException.SESSION_NOT_EXIST);
        if (sessions.containsKey(requestCode)) return sessions.get(requestCode);
        throw new NoSuchFieldException(SessionException.SESSION_NOT_EXIST);
    }

    /**
     * 当有新的用户新增时,
     *
     * @param user
     */
    public void set(User user) {
        if (user == null) throw new IllegalArgumentException(SessionException.REQUEST_CODE_ISNULL);
        if (Strings.isNullOrEmpty(user.getCode()))
            throw new IllegalArgumentException(SessionException.USER_CODE_ISNULL);
        Session session = new Session();
        session.setUser(user);
        session.setUpdateTime(System.currentTimeMillis() / 1000);
        session.setRequsetCode(user.getCode());
        sessions.put(user.getCode(), session);
    }

    /**
     * 把用户sesion从容器中清理出去
     *
     * @param requestCode 用户requestCode ,默认userCode
     */
    public void delete(String requestCode) {
        if (Strings.isNullOrEmpty(requestCode))
            throw new IllegalArgumentException(SessionException.REQUEST_CODE_ISNULL);
        if (sessions.containsKey(requestCode)) {
            sessions.remove(requestCode);
        }
    }

    public void update(User user) {
        if (user == null) throw new IllegalArgumentException(SessionException.REQUEST_CODE_ISNULL);
        if (Strings.isNullOrEmpty(user.getCode()))
            throw new IllegalArgumentException(SessionException.USER_CODE_ISNULL);
        Session session;
        if (sessions.containsKey(user.getCode())) session = sessions.get(user.getCode());
        else session = new Session();
        session.setUser(user);
        session.setRequsetCode(user.getCode());
        session.setUpdateTime(System.currentTimeMillis());
        sessions.put(user.getCode(), session);
    }

    /**
     * 当用户发起请求后,更新用户的session超时时间
     *
     * @param requestCode 用户requestCode ,默认userCode
     * @throws NoSuchFieldException 如果session属性不存在,则抛出异常
     */
    public void updateTime(String requestCode) throws NoSuchFieldException {
        if (Strings.isNullOrEmpty(requestCode))
            throw new IllegalArgumentException(SessionException.REQUEST_CODE_ISNULL);
        if (sessions.containsKey(requestCode)) {
            sessions.get(requestCode).setUpdateTime(System.currentTimeMillis());
        } else
            throw new NoSuchFieldException(SessionException.SESSION_NOT_EXIST);

    }

    /**
     * session 超时计时器
     */
    public void scheduler() {
        logger.info(SessionException.SESSIONMANAGER_START_TIME);
        timer.schedule(new MyTimerTask(), overTime, checkTime);
    }

    /**
     * 关闭session清理线程
     */
    public void cancel() {
        timer.cancel();
    }

    /**
     * 任务类,用来清理已经超时的session数据
     */
    class MyTimerTask extends TimerTask {
        @Override
        public void run() {
            logger.info(SessionException.SESSION_START_CLEAR);
            Set<Map.Entry<String, Session>> set = sessions.entrySet();
            Iterator<Map.Entry<String, Session>> iterator = set.iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, Session> entry = iterator.next();
                if (isOverTime(entry.getValue())) {
                    iterator.remove();
                    logger.info(SessionException.SESSION_CLEAR + ": code = " + entry.getKey());
                }
            }
            logger.info(SessionException.SESSION_CLEAR_OVER);
            System.gc();
        }
    }

    /**
     * session 对象
     */
    public class Session {
        String requsetCode;
        User user;
        long updateTime;

        public String getRequsetCode() {
            return requsetCode;
        }

        public void setRequsetCode(String requsetCode) {
            this.requsetCode = requsetCode;
        }

        public User getUser() {
            return user;
        }

        public void setUser(User user) {
            this.user = user;
        }

        public long getUpdateTime() {
            return updateTime;
        }

        public void setUpdateTime(long updateTime) {
            this.updateTime = updateTime;
        }
    }

}
